#include <i386/stdlib.h>
#include <i386/string.h>
#include <i386/limits.h>
#include <i386/float.h>
#include <i386/mem.h>
#include <stdarg.h>
#include <ctype.h>
#include <math.h>
#include "sprintf.h"

unsigned fcvt(double v, char *buffer, int width, int prec, int flag) {
	double ip, fp, val;
	register int l=0;
	register int digits;
	int conv, got_a_digit, exceeded, len = 0;
	char tmp[300];
	memset(tmp, 0, 300);
	
	// inf / NaN
	if (isspecial(v,buffer)) {
		return strlen(buffer);
	}
	
	// check for negative value and add optional + sign
	if (v < 0) {
		*buffer++ = '-';
		v = -v;
		len++;
	} else if (flag & ADD_PLUS) {
		*buffer++ = '+';
		len++;
	}
	
	// extract integer part and mantissa
	fp = modf(v, &ip);
	
	// integer part
	digits = 0;
	if (ip >= 1.0) {
		while (ip >= 1.0) {
			val = fmod(ip, 10.0);
			ip = ip / 10.0;
			tmp[digits++] = todigit((unsigned)(val));
		}
		len += digits;
		// reverse the temporary buffer into output buffer
		// translate the last 15 digits, since the others are beyond the limit
		// of double precision	
		for (l = digits-1; l >= max(digits-15, 0); l--) {
			*buffer++ = tmp[l];
		}
		
		if (l >= 0) for (l = digits-16; l >= 0; l--) {
			*buffer++ = '0';
		}
		
		*buffer = 0;
	} else {
		// 0 if IP == 0
		*buffer++ = '0';
		len++;
	}
	
	// Process fractional part according to width specification
	// if RESPECT_WIDTH is set, scan until we reach desired precision
	// else scan until we find a non-zero digit
	if (fp > 1e-307 && len < width+1) {
		*buffer++ = '.';
		len++;
		
		if (flag & RESPECT_WIDTH) {
			got_a_digit = 1;
		} else {
			got_a_digit = 0;
		}
		
		exceeded = 0;
		digits = 1;
		while (!exceeded) {
			// DBL_EPSILON used to correct rounding errors
			fp = (fp + DBL_EPSILON) * 10.0;
			fp = modf(fp, &ip);
			conv = (int)(ip);
			
			if (conv != 0 && !got_a_digit) {
				got_a_digit = 1;
			}
			
			*buffer++ = todigit(conv);
			len++;
			digits++;
			
			if (got_a_digit && (digits > prec)) {
				exceeded = 1;
			}
			
			if (width < len) {
				exceeded = 1;
			}
		}
		// remove trailing zeros after decimal point
		while (*--buffer == '0' && *(buffer-1) != '.') {
			len--;
		}
		buffer++;
	}
	
	*buffer = 0;
	return len;
}


